/**
 * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights
 * reserved. <a>http://www.cqcis.com</a>
 */
package com.cqcis.uip.base.framework.utils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;

/**
 * 对象工具类
 * 
 * @author huangmy
 * @date   2008-6-17
 */
public class ObjectUtil {
	private static final Map<Class<?>, BeanInfo> classCache = Collections.synchronizedMap(new WeakHashMap<Class<?>, BeanInfo>());
	
	/**
     * 参数是否为NULL，如果为NULL，抛出运行时异常
     * 
     * @param objects
     */
    public static void assertParamsNotNULL(Object... objects) {
    	if (objects == null) {
    		throw new NullPointerException("the param can't be null.");
    	}
    	
    	for (Object o : objects) {
    		if (o == null) {
    			throw new NullPointerException("the param can't be null.");
    		}
    	}
    }
    
    /**
     * 将MAP转换为bean
     * 
     * @param map
     * @return
     */
    public static Object convert(Map<String, Object> map, Class<?> clazz) {
    	assertParamsNotNULL(map, clazz);
    	
    	PropertyDescriptor[] pds = getPropertyDescriptors(clazz);
    	if (pds != null) {
    		Object bean = null; // 对象
    		try {
				bean = clazz.newInstance();
			} catch (InstantiationException e) {
				throw new RuntimeException(e);
			} catch (IllegalAccessException e) {
				throw new RuntimeException(e);
			}
			
    		for (PropertyDescriptor pd : pds) {
    			Method writeMethod = pd.getWriteMethod();    			
    			String name = pd.getName();    			
    			Object value = map.get(name);  
    			Class<?> type = null;
    			if (value != null) {
    				try {
    					Class<?>[] paramTypes = writeMethod.getParameterTypes();
    	    			type = paramTypes[0];
    	    			    	    			
    	    			if (type.equals(String.class)) {
    	    				value = value.toString();
    	    			}
    	    			    	    			
    	    			value = type.cast(value);
						writeMethod.invoke(bean, value);
					} catch (IllegalArgumentException e) {
						throw new RuntimeException("name=" + name + ", value=" + value + ", paramType=" + type,e);
					} catch (IllegalAccessException e) {
						throw new RuntimeException("name=" + name + ", value=" + value + ", paramType=" + type,e);
					} catch (InvocationTargetException e) {
						throw new RuntimeException("name=" + name + ", value=" + value + ", paramType=" + type,e);
					}
    			}    			
    		}
    		
    		return bean;
    	}
    	
    	return null;
    }
    
    /**
     * 将JavaBean转换为 KEY-VALUE(属性名, 属性值)方式表示
     * 
     * @param bean 
     * @return
     */
    @SuppressWarnings("unchecked")
	public static Map<String, Object> convert(Object bean) {
    	ObjectUtil.assertParamsNotNULL(bean);
    	
    	if (bean instanceof Map) {
    		return (Map<String, Object>)bean;
    	}
    	
    	PropertyDescriptor[] pds = getPropertyDescriptors(bean.getClass());
    	if (pds != null) {
    		Map<String, Object> props = new HashMap<String, Object>();
    		for (PropertyDescriptor pd : pds) {
    			String name = pd.getName(); 
    			Object value = null;
    			
    			if ("class".equals(name)) {
					continue;
				}

				try {
					Method readMethod = pd.getReadMethod();
					if (readMethod == null) {
						throw new RuntimeException("Can't find the 'ReadMethod' for property '" + pd.getName() + "'");
					}
					value = readMethod.invoke(bean);
				} catch (IllegalArgumentException e) {
					throw new RuntimeException(e);
				} catch (IllegalAccessException e) {
					throw new RuntimeException(e);
				} catch (InvocationTargetException e) {
					throw new RuntimeException(e);
				}

				props.put(name, value != null ? value : "");    			
    		}
    		
    		return props;
    	}
    	
    	return null;
    }
    
    /**
     * 将对象列表转换为类型-值表示
     * 
     * @param objects
     * @return
     */
    public static TypeValue[] convertToType(Object...objects) {
    	if (objects == null) {
    		return null;
    	}
    	
    	TypeValue[] typeValues = new TypeValue[objects.length];
    	
    	for (int i = 0; i < objects.length; i ++) {
    		Object o = objects[i];
    		if (o == null) {
    			typeValues[i] = new TypeValue(null, o);
    			continue;
    		}
    		
    		Class<?> type = o.getClass();
    		
    		if (type.equals(String.class)) {
    			type = String.class;                
            } else if (type.equals(Integer.TYPE) || type.equals(Integer.class)) {
            	type = Integer.class;
            } else if (type.equals(Boolean.TYPE) || type.equals(Boolean.class)) {
            	type = Boolean.class;
            } else if (type.equals(Long.TYPE) || type.equals(Long.class)) {
            	type = Long.class;
            } else if (type.equals(Double.TYPE) || type.equals(Double.class)) {
            	type = Double.class;
            } else if (type.equals(Float.TYPE) || type.equals(Float.class)) {
            	type = Float.class;
            } else if (type.equals(Short.TYPE) || type.equals(Short.class)) {
            	type = Short.class;
            } else if (type.equals(Byte.TYPE) || type.equals(Byte.class)) {
            	type = Byte.class;
            } else if (type.equals(Timestamp.class)) {
            	type = Timestamp.class;
            }
    		
    		typeValues[i] = new TypeValue(type, o);
    	}
    	
    	return typeValues;
    }
    
    /**
    * 获取给定class的bean属性描述
    * 
    * @param c
    * @return
    */
   private static PropertyDescriptor[] getPropertyDescriptors(Class<?> c) {		
		BeanInfo beanInfo = classCache.get(c);
		if (beanInfo != null) {
			return beanInfo.getPropertyDescriptors();
		}
		
		try {
			beanInfo = Introspector.getBeanInfo(c);
			classCache.put(c, beanInfo);
		} catch (IntrospectionException e) {
			throw new RuntimeException("Bean introspection failed: " + e.getMessage());
		}
		
		if (beanInfo == null) {
			throw new RuntimeException("can't find beanInfo for the class.");
		}

		return beanInfo.getPropertyDescriptors();
	}
    
    /**
     * 类型，值描述
     */
    public static class TypeValue {
    	private Class<?> type; // 类型
    	private Object value; // 值
    	
    	public TypeValue() {    		
    	}
    	
    	public TypeValue(Class<?> type, Object value) {    		
    		this.type = type;
    		this.value = value;
    	}
    	
		public Class<?> getType() {
			return type;
		}
		public void setType(Class<?> type) {
			this.type = type;
		}
		public Object getValue() {
			return value;
		}
		public void setValue(Object value) {
			this.value = value;
		}
    }
}
